﻿#region (C) Header Region @ 2012
//====================================================
// 文件: UrlRewriterSetting.cs
// 描述: URL重写帮助类
// 路径: Antu.Core\Components\UrlRewriterSetting.cs
// ******************版本1 ******************
// 人员: 蔡金保    时间 : 2012/11/15 11:25:26
// 注释:
//====================================================
#endregion

using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.Data;
using System.Text.RegularExpressions;
using Antu.Core.Logger;
using System.Xml;
using Antu.Core.Services;

namespace Antu.Core.Services
{
    /// <summary>
    /// Url重写，配置文件可以跟UrlRewriter.Net2.0配置相同皆可
    /// </summary>
    public sealed class UrlRewriterService : AbstractService
    {
        /// <summary>
        /// URL转发
        /// </summary>
        internal UrlRewriterService()
        {
        }
        private string rewriterConfig = "~/ConfigSettings/UrlRewriteSetting.config";

        private List<UrlInfo> _urlInfolist = new List<UrlInfo>();
        private void FillConfigList()
        {
            DataSet ds = new DataSet();
            ds.ReadXml(HttpContext.Current.Server.MapPath(rewriterConfig));
            if (ds.Tables.Count > 0)
            {
                foreach (DataRow row in ds.Tables[0].Rows)
                {
                    UrlInfo urlInfo = new UrlInfo();
                    urlInfo.Url = row["url"].ToString().Trim();
                    urlInfo.To = row["to"].ToString().Trim();
                    _urlInfolist.Add(urlInfo);
                }
            }
            ds.Dispose();
        }

        private string ResolveUrl(string appPath, string url)
        {
            if (url.Length == 0 || url[0] != '~')
                return url;
            else
            {
                if (url.Length == 1)
                    return appPath;
                if (url[1] == '/' || url[1] == '\\')
                {
                    if (appPath.Length > 1)
                        return appPath + "/" + url.Substring(2);
                    else
                        return "/" + url.Substring(2);
                }
                else
                {
                    if (appPath.Length > 1)
                        return appPath + "/" + url.Substring(1);
                    else
                        return appPath + url.Substring(1);
                }
            }
        }
        private void RewriterMark()
        {
            if (!HttpContext.Current.Items.Contains("UrlRewriter"))
            {
                HttpContext.Current.Items.Add("UrlRewriter", true);
            }
        }

        private void RewriteUrl(HttpContext context, string sendToUrl)
        {
            string x, y;
            RewriteUrl(context, sendToUrl, out x, out y);
        }
        private void RewriteUrl(HttpContext context, string sendToUrl, out string sendToUrlLessQString, out string filePath)
        {
            if (context.Request.QueryString.Count > 0)
            {
                if (sendToUrl.IndexOf('?') != -1)
                    sendToUrl += "&" + context.Request.QueryString.ToString();
                else
                    sendToUrl += "?" + context.Request.QueryString.ToString();
            }
            string queryString = String.Empty;
            sendToUrlLessQString = sendToUrl;
            if (sendToUrl.IndexOf('?') > 0)
            {
                sendToUrlLessQString = sendToUrl.Substring(0, sendToUrl.IndexOf('?'));
                queryString = sendToUrl.Substring(sendToUrl.IndexOf('?') + 1);
            }

            filePath = string.Empty;
            filePath = context.Server.MapPath(sendToUrlLessQString);
            string pathInfo = context.Request.PathInfo;
            try
            {
                context.RewritePath(sendToUrlLessQString, pathInfo, queryString);
            }
            catch (Exception e)
            {
                LogManager.Manager.OutputErrorLog(e, new object[] { context, sendToUrl, sendToUrlLessQString, filePath });
            }

        }
        public bool Rewrite(HttpContext context)
        {
            if (context != null)
            {
                string requestedPath = context.Request.Path;
                context.Trace.Write("CbHttpModule_UrlRewriter", "启动CbHttpModule_UrlRewriter");
                if (_urlInfolist.Count > 0)
                {
                    for (int i = 0; i < _urlInfolist.Count; i++)
                    {
                        string url = "^" + ResolveUrl(HttpContext.Current.Request.ApplicationPath, _urlInfolist[i].Url) + "$";
                        Regex regex = new Regex(url, RegexOptions.IgnoreCase);

                        if (regex.IsMatch(requestedPath))
                        {
                            RewriterMark();
                            string to = ResolveUrl(context.Request.ApplicationPath, regex.Replace(requestedPath, _urlInfolist[i].To));
                            if (!string.IsNullOrEmpty(to))
                            {
                                context.Trace.Write("CbHttpModule_UrlRewriter", "转发URL到" + to);
                                RewriteUrl(context, to);
                            }
                            break;
                        }
                        context.Trace.Write("CbHttpModule_UrlRewriter", "CbHttpModule_UrlRewriter结束");
                    }
                    return true;
                }
                return false;
            }
            else
            {
                return false;
            }
        }

        /// <summary>
        /// 初始化服务
        /// </summary>
        public override void InitializeService()
        {
            FillConfigList();
            base.InitializeService();
        }
        /// <summary>
        /// 卸载服务
        /// </summary>
        public override void UnloadService()
        {
            _urlInfolist = new List<UrlInfo>();
            base.UnloadService();
        }
    }

    /// <summary>
    /// 重写Ur结构体，包含虚假Url与真实Urll
    /// </summary>
    public struct UrlInfo
    {
        private string _url;
        public string Url
        {
            get { return this._url; }
            set { this._url = value; }
        }
        private string _to;
        public string To
        {
            get { return this._to; }
            set { this._to = value; }
        }
    }
}
